/*
 *  Algorithm.h
 *  IncrementalAlgorithmSerial
 *
 *  Created by Roman Kutlak on 30/10/2010.
 *  Copyright 2010 Roman Kutlak. All rights reserved.
 *
 */

#ifndef _ALGORITHM_H_ 
#define _ALGORITHM_H_

#include <string>
#include <vector>

#include "KnowledgeBase.h"
#include "Ontology.h"
#include "AlgorithmFunctions.h"

namespace kutlak {
namespace roman {
namespace gre {
    
    class Property;
    class Entity;
    
    
    /*! \brief Abstract class that provides an universal interface to the GRE algorithms.
     * The class has handles for allowing plural, conjunction, negation, disjuncion and 
     * gradable properties. The algorithms do not necessarily support the functionality.
     * E.G. algorithm might treat gradable property as a normal property.
     *
     * The algorithm manges a smart pointer to a KnowledgeBase and an Ontology.
     * The Ontology might or might not be used.
     * The KnowledgeBase is necessary for the correct function of the algorithm
     * but any subclass should check that the KnowledgeBase is set as it is empty
     * uppon the construction of the object.
     */
    class Algorithm {
    public:
#pragma mark -
#pragma mark lifecycle 
        /*! \brief Default constructor might not be used as this is an abstract class.
         *  The algorithm can optionally take path to the KnowledgeBase.
         */
        Algorithm(const pKnowledgeBase& kb = pKnowledgeBase(),
                  const pOntology& ontology = pOntology(),
                  const std::string& name = "");
        
        Algorithm(const Algorithm& from) = delete;
        
        Algorithm& operator=(const Algorithm& rhs) = delete;
        
        //! Virtual destructor.
        virtual ~Algorithm() = default;
        
#pragma mark -
#pragma mark operations
        /*! \brief the method generates a referring expression for an entity.
         *  This is an abstract method that has to be implemented by any subclass
         *  that extends the Algorithm.
         \param referent is the entity for which we generate the referring expression.
         \return referring expression. The expression is only on the content level
         and will need to be realised. It is probably a list of Properties.
         */
        virtual RefExp MakeReferringExpression(const EntityPtrT& referent,
                                               ContainerT distractors) = 0;
        
    protected:
        RefExp MRE(const std::string& referentName);
        
#pragma mark -
#pragma mark access
    public:
        // No need for a flag? Just overload the MakeRefferingExpression() to take a list
        void SetPlural(bool flag) { fPlural = flag; }
        bool Plural() const { return fPlural; }
        
        void SetNegation(bool flag) { fNegation = flag; }
        bool Negation() const { return fNegation; }
        
        void SetDisjunction(bool flag) { fDisjunction = flag; }
        bool Disjunction() const { return fDisjunction; }
        
        // Assumed by default
        void SetConjunction(bool flag) { fConjunction = flag; }
        bool Conjunction() const { return fConjunction; }
        
        void SetGradable(bool flag) { fGradable = flag; }
        bool Gradable() const { return fGradable; }
        
        void SetDeterminer(bool flag) { fDeterminer = flag; }
        bool UseDeterminer() const { return fDeterminer; }
        
        //! Method returns a pointer to the KnowledgeBase.
        pKnowledgeBase KnowledgeBase() { return mpKnowledgeBase; }
        
        //! Method sets new KnowledgeBase. It creates a copy.
        void SetKnowledgeBase(const pKnowledgeBase& kb) {
            mpKnowledgeBase = kb;
        }
        
        //! Method returns a pointer to the used Ontology.
        pOntology Ontology() { return mpOntology; }
        
        //! Method sets new Ontology. It creates a copy.
        void SetOntology(const pOntology& onto) {
            mpOntology = onto;
        }
        
        void BanAttribute(const Vindex_t& attribute);
        void AllowAttribute(const Vindex_t& attribute);
        bool IsBannedAttribute(const Vindex_t& attribute);
        
        void BanAttribute(const std::string& attribute);
        void AllowAttribute(const std::string& attribute);
        bool IsBannedAttribute(const std::string& attribute);
        
        const std::string& Name() const {
            return mName;
        }
        
    protected:
        bool fPlural;
        bool fNegation;
        bool fDisjunction;
        bool fConjunction;
        bool fGradable;
        bool fDeterminer;
        
        std::string mName;
        std::vector<Vindex_t> mBannedAttributes;
        
        pKnowledgeBase mpKnowledgeBase;
        pOntology      mpOntology;
    };
    
}
}
}

#endif
